package com.alks.function.service.serviceImpl.finance.salary;

import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.utils.DateUtils;
import com.alks.common.utils.beanutils.ObjectUtils;
import com.alks.common.utils.excelUtils.ExcelPoiUtils;
import com.alks.common.utils.excelUtils.ExcelUtils;
import com.alks.entity.data.entity.PcBonusEndMonth;
import com.alks.entity.data.entity.PcStitchProdDetail;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.finance.salary.SalaryStitchInventoryDto;
import com.alks.function.data.request.finance.salary.*;
import com.alks.function.mapper.finance.salary.SalaryStitchInventoryMapper;
import com.alks.function.mapper.finance.salary.SealAccountMapper;
import com.alks.function.service.finance.salary.SalaryStitchInventoryService;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SalaryStitchInventoryServiceImpl implements SalaryStitchInventoryService {

    @Autowired
    private SalaryStitchInventoryMapper salaryStitchInventoryMapper;

    @Autowired
    private SealAccountMapper sealAccountMapper;

    /**
     * 指令产量明细
     * @param request
     * @return
     */
    @Override
    @AutoPageAop
    public ResponseInfo  getLotProductDetails(SalaryStitchInventoryRequest request) {
        String companyId = UserIdThread.get().getCompanyId();
        List<SalaryStitchInventoryDto> list = salaryStitchInventoryMapper.getLotProductDetails(companyId,request);

        HashMap map = new HashMap<>();
        PageInfo page = new PageInfo(list);
        map.put("total",page.getTotal());
        map.put("list",list);
        return ResponseInfo.ok(map);
    }

        /**
     * 查询指令产量明细的完工数量和金额
     * @param request
     * @return
     */
    @Override
    public ResponseInfo getLotProductCount(SalaryStitchInventoryRequest request) {
        String companyId = UserIdThread.get().getCompanyId();
        SalaryStitchInventoryDto dto = salaryStitchInventoryMapper.getLotProductCount(companyId,request);

        //完工数量和金额
        BigDecimal countQty = BigDecimal.ZERO ;
        BigDecimal countAmt = BigDecimal.ZERO ;
        if(ObjectUtils.isNotEmpty(dto)){
            countQty = countQty.add(Optional.ofNullable(dto.getQty()).orElse(BigDecimal.ZERO));
            countAmt = countAmt.add(Optional.ofNullable(dto.getAmt()).orElse(BigDecimal.ZERO));

            // 如果dto.getPrice()或dto.getAmt()为null或0，则设置为null
            dto.setPrice(Optional.ofNullable(dto.getPrice())
                    .filter(p -> !p.equals(BigDecimal.ZERO))
                    .orElse(null));
            dto.setAmt(Optional.ofNullable(dto.getAmt())
                        .filter(a -> !a.equals(BigDecimal.ZERO))
                        .orElse(null));
        }

        HashMap map = new HashMap<>();
        map.put("countQty",countQty);
        map.put("countAmt",countAmt);
        return ResponseInfo.ok(map);
    }
    /**
     * 结算确认
     * @return
     */
    @Override
    @Transactional
    public ResponseInfo getSettleAccounts(SalaryStitchRequest2 request) {
        int flag = request.getOperateFlag();
        if(flag== 1 && (StringUtils.isEmpty(request.getFinanceYymm()) || StringUtils.isEmpty(request.getAccountName()))){
            throw new ServiceErrorException("请输入结算月份、结算方式！");
        }
        if(flag== 3 && StringUtils.isEmpty(request.getRemark())){
            throw new ServiceErrorException("请输入备注信息！");
        }
        //List<SalaryStitchRequest> list = request.getList();
        String companyId = UserIdThread.get().getCompanyId();
        List<SalaryStitchInventoryDto> list = salaryStitchInventoryMapper.getLotProductDetails(companyId,request.getRequest());
        if(ObjectUtils.isEmpty(list)){
            throw new ServiceErrorException("没有查到数据");
        }
        //存在单价为空或单价为未检验的资料
        boolean flag1 = list.stream()
                .anyMatch(item -> item.getPrice() == null || item.getPrice().equals(0.0));
        // 检查是否存在单价为空或单价为未检验（0.0）的资料，并提取对应的lotNo
        Set<String> priceList = list.stream()
                .filter(item -> item.getPrice() == null || item.getPrice().equals(0.0))
                .map(SalaryStitchInventoryDto::getLotNo)
                .collect(Collectors.toSet());

        boolean flag12 = list.stream()
                .anyMatch(item -> item.getPriceCfmFlag() == null);
        Set<String> priceCfmList = list.stream()
                .filter(item -> item.getPriceCfmFlag() == null)
                .map(SalaryStitchInventoryDto::getLotNo)
                .collect(Collectors.toSet());

        if(flag == 1 && flag1){
            throw new ServiceErrorException( String.join(", ", priceList) + "记录存在单价为空资料!");
        }
        if(flag == 1 && flag12){
            throw new ServiceErrorException(String.join(", ", priceCfmList) + "记录存在单价未检核的资料!");
        }

        //已经封账
        boolean flag2 = list.stream()
                .anyMatch(item -> item.getBonusFlag() != null && item.getBonusFlag().equals("Y"));
        Set<String> bonusList = list.stream()
                .filter(item -> item.getBonusFlag() != null && item.getBonusFlag().equals("Y"))
                .map(SalaryStitchInventoryDto::getLotNo)
                .collect(Collectors.toSet());
        if((flag == 1 || flag == 2) && flag2){
            throw new ServiceErrorException(String.join(", ", bonusList) + "存在已封账的资料，不能结算或者取消结算处理，请检查！");
        }
        //存在已经结算过的
        boolean flag3 = list.stream()
                .anyMatch(item -> item.getCheckFlag() != null && item.getCheckFlag().equals("Y"));
        if(flag == 1 && flag3){
            throw new ServiceErrorException("存在已结算的资料，请检查！");
        }
        if(flag == 2 && !flag3){
            throw new ServiceErrorException("存在未结算的资料，请检查！");
        }


        List<PcStitchProdDetail> detailList = new ArrayList<>();
        for (SalaryStitchInventoryDto stitchRequest : list) {
            PcStitchProdDetail detail = new PcStitchProdDetail();
            BeanUtils.copyProperties(stitchRequest,detail);
            detail.setSeqNo(BigDecimal.valueOf(stitchRequest.getSeqNo()));
            if(flag == 1){
                detail.setFinanceDate(String.valueOf(LocalDateTime.now()));
                detail.setFinanceYymm(request.getFinanceYymm());
                detail.setFinanceUser(UserIdThread.get().getUserName());
                detail.setAccountName(request.getAccountName());
                detail.setCheckFlag("Y");
                detailList.add(detail);
            }else if(flag == 2){
                detail.setFinanceDate(null);
                detail.setFinanceYymm(null);
                detail.setFinanceUser(null);
                detail.setAccountName(null);
                detail.setCheckFlag(null);
                detailList.add(detail);
            }else if(flag == 3){
                detail.setRemark(request.getRemark());
                detailList.add(detail);
            }
        }
        int count = salaryStitchInventoryMapper.updateBatchPcStitchProdDetail(companyId,detailList);

        if(flag == 1){
            if(count > 0){
                return ResponseInfo.ok("结算成功");
            }else{
                throw new ServiceErrorException("结算失败");
            }
        }else if(flag == 2){
            if(count > 0){
                return ResponseInfo.ok("取消结算成功");
            }else{
                throw new ServiceErrorException("取消结算失败");
            }
        }else if(flag == 3){
            if(count > 0){
                return ResponseInfo.ok("财务备注成功");
            }else{
                throw new ServiceErrorException("财务备注失败");
            }
        }else{
            throw new ServiceErrorException("操作标识错误");
        }
    }

    /**
     * 导出
     * @param request
     * @param response
     */
    @Override
    public void export(SalaryStitchInventoryRequest request, HttpServletResponse response)  throws IOException {
        String companyId = UserIdThread.get().getCompanyId();
        List<SalaryStitchInventoryDto> list = salaryStitchInventoryMapper.getLotProductDetails(companyId,request);

        //金额
        BigDecimal countAmt = BigDecimal.ZERO ;
        if(ObjectUtils.isNotEmpty(list)){
            // 遍历list
            for (SalaryStitchInventoryDto dto : list) {
                if(dto.getBonusym() != null){
                    dto.setBonusFlag("Y");
                }

                countAmt = countAmt.add(Optional.ofNullable(dto.getAmt()).orElse(BigDecimal.ZERO));

                // 如果dto.getPrice()或dto.getAmt()为null或0，则设置为null
                dto.setPrice(Optional.ofNullable(dto.getPrice())
                        .filter(p -> !p.equals(BigDecimal.ZERO))
                        .orElse(null));
                dto.setAmt(Optional.ofNullable(dto.getAmt())
                        .filter(a -> !a.equals(BigDecimal.ZERO))
                        .orElse(null));
            }
        }

        Map<String, Object> map = new HashMap<>();
        map.put("countAmt",countAmt);
        map.put("list",list);

        TemplateExportParams templateParams = new TemplateExportParams("templates/针车件资模板.xlsx", true);
        templateParams.setColForEach(true);
        String fileName = "针车件资_" + DateUtils.dateTimeNow() + ".xlsx";
        try {
            if(list.size() >= 60000 ){
                ExcelUtils.setResponseZIP(response, fileName);
                ExcelPoiUtils.writeExceBatchlListZIP(response,fileName,  map, templateParams,60000);
            }else{
                ExcelUtils.setResponseZF(response, fileName);
                ExcelPoiUtils.writeExcelList1(response,  map, templateParams);
            }
        } catch (Exception e) {
            log.error("导出失败, 错误信息: {}", e.getMessage());
            throw new ServiceErrorException("导出失败!");
        }
    }

    /**
     * 导出月份汇总
     * @param request
     * @param response
     */
    @Override
    public void exportMonthSummary(SalaryStitchInventoryRequest request, HttpServletResponse response)  throws IOException {
        String companyId = UserIdThread.get().getCompanyId();
        //判断是否有数据
        if (ObjectUtils.isEmpty(request.getFinanceYymm())){
            throw new ServiceErrorException("请输入检核月份");
        }
        //判断是否封账：已经封账的不能导出
//        PcBonusEndMonthRequest bonusEndMonthRequest = new PcBonusEndMonthRequest();
//        bonusEndMonthRequest.setBonusYM(request.getFinanceYymm());
//        bonusEndMonthRequest.setBonusType("STITCH");
//        List<PcBonusEndMonth> bonusYM = sealAccountMapper.getProductAccountDetails(companyId,bonusEndMonthRequest);
//        if(ObjectUtils.isNotEmpty(bonusYM)){
//            throw new ServiceErrorException("该月份已经封账！");
//        }

        //根据指令查询所有该月份指令汇总
        List<SalaryStitchInventoryDto> list = salaryStitchInventoryMapper.getMonthSummaryDetails(companyId,request);

        Map<String, Object> map = new HashMap<>();
        map.put("financeYymm",request.getFinanceYymm());
        map.put("list",list);

        TemplateExportParams templateParams = new TemplateExportParams("templates/针车计件汇总模板.xlsx", true);
        templateParams.setColForEach(true);
        String fileName = "针车计件汇总_" + DateUtils.dateTimeNow() + ".xlsx";
        try {
            if(list.size() >= 60000 ){
                ExcelUtils.setResponseZIP(response, fileName);
                ExcelPoiUtils.writeExceBatchlListZIP(response,fileName,  map, templateParams,60000);
            }else{
                ExcelUtils.setResponseZF(response, fileName);
                ExcelPoiUtils.writeExcelList1(response,  map, templateParams);
            }
        } catch (Exception e) {
            log.error("导出失败, 错误信息: {}", e.getMessage());
            throw new ServiceErrorException("导出失败!");
        }
    }

    /**
     * 导出员工汇总
     * @param request
     * @param response
     */
    @Override
    public void exportEmployeeSummary(SalaryStitchInventoryRequest request, HttpServletResponse response) throws IOException {
        //判断：请输入起止派工时间或检核月份或指令其他的查询条件
        Boolean flag = ObjectUtils.isEmpty(request.getDateStart1()) && ObjectUtils.isEmpty(request.getDateEnd1())
                && ObjectUtils.isEmpty(request.getProcessName()) && ObjectUtils.isEmpty(request.getLotNo())
                && ObjectUtils.isEmpty(request.getStyle()) && ObjectUtils.isEmpty(request.getBalanceNo())
                && ObjectUtils.isEmpty(request.getFinanceYymm()) && ObjectUtils.isEmpty(request.getDeptName())
                && ObjectUtils.isEmpty(request.getWorkName());
        if(flag){
            throw new ServiceErrorException("请输入起止派工时间或检核月份或指令其他的查询条件");
        }

        String companyId = UserIdThread.get().getCompanyId();
        List<SalaryStitchInventoryDto> list = salaryStitchInventoryMapper.getEmployeeSummary(companyId,request);

        //金额
        BigDecimal countAmt = BigDecimal.ZERO ;
        if(ObjectUtils.isNotEmpty(list)){

            // 遍历list
            for (SalaryStitchInventoryDto dto : list) {
                countAmt = countAmt.add(Optional.ofNullable(dto.getAmt()).orElse(BigDecimal.ZERO));
                // 如果dto.getPrice()或dto.getAmt()为null或0，则设置为null
                dto.setPrice(Optional.ofNullable(dto.getPrice())
                        .filter(p -> !p.equals(BigDecimal.ZERO))
                        .orElse(null));
                dto.setAmt(Optional.ofNullable(dto.getAmt())
                        .filter(a -> !a.equals(BigDecimal.ZERO))
                        .orElse(null));
            }
        }

        Map<String, Object> map = new HashMap<>();
        map.put("countAmt",countAmt);
        map.put("list",list);

        TemplateExportParams templateParams = new TemplateExportParams("templates/针车件资模板.xlsx", true);
        templateParams.setColForEach(true);
        String fileName = "针车件资_" + DateUtils.dateTimeNow() + ".xlsx";
        try {
            if(list.size() >= 60000 ){
                ExcelUtils.setResponseZIP(response, fileName);
                ExcelPoiUtils.writeExceBatchlListZIP(response,fileName,  map, templateParams,60000);
            }else{
                ExcelUtils.setResponseZF(response, fileName);
                ExcelPoiUtils.writeExcelList1(response,  map, templateParams);
            }
        } catch (Exception e) {
            log.error("导出失败, 错误信息: {}", e.getMessage());
            throw new ServiceErrorException("针车件资员工汇总导出失败!");
        }
    }

    /**
     * 导出员工汇总pdf
     * @param request
     * @return
     */
    @Override
    public ResponseInfo exportEmployeeSummaryByPdf(SalaryStitchInventoryRequest request) {
        //判断：请输入起止派工时间,指令,型体，结算单号，结算月份，组别，员工
        Boolean flag = ObjectUtils.isEmpty(request.getDateStart1()) && ObjectUtils.isEmpty(request.getDateEnd1())
                && ObjectUtils.isEmpty(request.getProcessName()) && ObjectUtils.isEmpty(request.getLotNo())
                && ObjectUtils.isEmpty(request.getStyle()) && ObjectUtils.isEmpty(request.getBalanceNo())
                && ObjectUtils.isEmpty(request.getFinanceYymm()) && ObjectUtils.isEmpty(request.getDeptName())
                && ObjectUtils.isEmpty(request.getWorkName());
        if(flag){
            throw new ServiceErrorException("请输入起止派工时间或检核月份或指令其他的查询条件");
        }
        //查询页面数据
        String companyId = UserIdThread.get().getCompanyId();
        List<SalaryStitchInventoryDto> list = salaryStitchInventoryMapper.getEmployeeSummaryByPdf(companyId,request);

        // 要展示的数据
        List<EmployeeSummary> summaryList = new ArrayList<>();
        // 计算所有 datePageList 的总数量
        int total = 0;

        if (ObjectUtils.isNotEmpty(list)) {
            Map<String, EmployeeSummary> summaryMap = new HashMap<>();
            List<String> headerList = Arrays.asList("类型", "型体","指令", "序号", "工序名称", "订单数", "派工双数", "单价", "金额", "结算月份");

            // 遍历list
            for (SalaryStitchInventoryDto dto : list) {
                // 创建一个键，用于分组
//                String key = dto.getLotNo() + dto.getDeptName() + dto.getWorkId() + dto.getWorkName();
                //String key = dto.getDeptName() + dto.getWorkId() + dto.getWorkName();
                String key = dto.getWorkDeptNo() + dto.getWorkId() + dto.getWorkName();

                // 如果当前key没有在map中，创建一个新的EmployeeSummary并初始化
                if (!summaryMap.containsKey(key)) {
                    EmployeeSummary es = new EmployeeSummary();
                    es.setWorkName(dto.getWorkName() != null ? dto.getWorkName() : "");
                    //es.setDeptName(dto.getDeptName() != null ? dto.getDeptName() : "");
                    es.setDeptName(dto.getWorkDeptName() != null ? dto.getWorkDeptName() : "");
                    //下单时间
                    String dateStart1 = request.getDateStart1();
                    String dateEnd1 = request.getDateEnd1();
                    String formattedStartDate = dateStart1 !=null ? (dateStart1.substring(5, 7) + "/" + dateStart1.substring(8, 10)) : "01/01";
                    String formattedEndDate = dateEnd1 !=null ? dateEnd1.substring(5, 7) + "/" + dateEnd1.substring(8, 10) : "01/01";

                    es.setSlipDate(formattedStartDate + "-" + formattedEndDate);
                    es.setDateList(new ArrayList<>()); // 初始化dateList
                    //es.getDateList().add(headerList); // 添加标题行
                    es.setCountQty(BigDecimal.ZERO); // 初始化countQty为0
                    es.setCountAmt(BigDecimal.ZERO); // 初始化countAmt为0
                    summaryMap.put(key, es);
                    summaryList.add(es); // 添加到summaryList中
                }

                // 获取对应的EmployeeSummary
                EmployeeSummary es = summaryMap.get(key);

                // 将数据添加到当前的EmployeeSummary
                List<String> rowList = new ArrayList<>();
                rowList.add(dto.getType() != null ? dto.getType() : "");
                //rowList.add(dto.getSlipDate() != null ? dto.getSlipDate() : ""); 又不按照生产日期了
                rowList.add(dto.getStyle() != null ? dto.getStyle() : "");
                rowList.add(dto.getLotNo() != null ? dto.getLotNo() : "");
                rowList.add(dto.getSeqNo() != 0 ? String.valueOf(dto.getSeqNo()) : "");
                rowList.add(dto.getProcessName() != null ? dto.getProcessName() : "");
                rowList.add(String.valueOf(dto.getOrdQty() != null ? dto.getOrdQty() : ""));
                rowList.add(String.valueOf(dto.getQty() != null ? dto.getQty() : ""));
                rowList.add(String.valueOf(dto.getPrice() != null ? dto.getPrice() : ""));
                rowList.add(String.valueOf(dto.getAmt() != null ? dto.getAmt() : ""));
                rowList.add(dto.getFinanceYymm() != null ? dto.getFinanceYymm() : "");
                //rowList.add(dto.getRemark() != null ? dto.getRemark() : "");
                es.getDateList().add(rowList);

                // 同种条件下的总和
                BigDecimal qty = Optional.ofNullable(dto.getQty()).orElse(BigDecimal.ZERO);
                BigDecimal countQty = es.getCountQty();
                BigDecimal countAmt = es.getCountAmt();

                // 更新累计值
                // 更新累计值
                es.setCountQty(countQty.add(qty));
                es.setCountAmt(countAmt.add(Optional.ofNullable(dto.getAmt()).orElse(BigDecimal.ZERO)));
                if(ObjectUtils.isNotEmpty(es.getDateList())){
                    es.setSize(es.getDateList().size());
                }

                //分页逻辑
                es.setDatePageList(groupElements(
                        es.getDateList(),
                        request.getPageSize(),
                        es.getCountQty(),
                        es.getCountAmt()));
            }

            //for (EmployeeSummary employeeSummary : summaryList) {
            //    int size = employeeSummary.getDatePageList().size();
            //    total += size;
            //}

            // 使用并行流来加速处理大列表
             total = summaryList.parallelStream()
                    .mapToInt(es -> es.getDatePageList() == null ? 0 : es.getDatePageList().size())
                    .sum();
        }

        // 创建一个日期格式器
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 获取当前日期
        Date currentDate = new Date();
        // 使用格式器格式化当前日期
        String formattedDate = sdf.format(currentDate);

        HashMap map = new HashMap<>();
        //PageInfo page = new PageInfo(summaryList);
        map.put("total",total);
        map.put("printDate",formattedDate);
        map.put("list",summaryList);
        return ResponseInfo.ok(map);
    }

    /**
     * 修改 groupElements 方法以适应 List<List<String>> 类型的输入
     * @param source
     * @param pageSize
     * @param countQty 派工数量
     * @param countAmt 派工金额
     * @return
     */
    private List<List<List<String>>> groupElements(List<List<String>> source, int pageSize ,BigDecimal countQty, BigDecimal countAmt) {
        List<String> headerList = Arrays.asList("类型", "型体","指令", "序号", "工序名称", "订单数", "派工双数", "单价", "金额", "结算月份");

        List<List<List<String>>> result = new ArrayList<>();
        int size = source.size();

        // 计算总页数
        int totalPages = (int) Math.ceil((double) size / pageSize);

        for (int i = 0; i < size; i += pageSize) {
            // 创建一个新的分页子列表
            List<List<String>> page = new ArrayList<>();

            // 添加 headerList 作为页面的第一个元素
            page.add(new ArrayList<>(headerList));

            // 计算结束索引，避免超出列表范围
            int end = Math.min(i + pageSize, size);

            // 使用subList方法获取子列表并添加到当前页面中
            for (int j = i; j < end; j++) {
                page.add(new ArrayList<>(source.get(j)));
            }

            // 将当前页面添加到结果集中
            result.add(page);

            // 检查是否为最后一页，并在最后一页添加汇总行
            if ((i / pageSize) + 1 == totalPages) {
                // 创建汇总行
                List<String> summaryRow = Arrays.asList(
                        //"", "", "", "", "",  "", "总计", 说多了个空，要往前推
                        "", "", "", "", "",  "总计",
                        String.format("%.2f", countQty),
                        "总计",
                        String.format("%.2f", countAmt),
                        "", ""
                );
                // 添加汇总行到页面
                page.add(summaryRow);
            }
        }

        return result;
    }

}
